#include <string.h>
#include <jni.h>
#include <stdio.h>
#include <android/log.h>
#include "AESEncrypt.h"

#include <stdlib.h>
#include <fcntl.h>
#include "zipmem.h"

 #ifndef LOG_TAG

 #define LOG_TAG    "test"

 #define LOGD(...)  __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)

 #define LOGI(...)  __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)

 #define LOGW(...)  __android_log_print(ANDROID_LOG_WARN,LOG_TAG,__VA_ARGS__)

 #define LOGE(...)  __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)

 #define LOGV(...)  __android_log_print(ANDROID_LOG_VERBOSE,LOG_TAG,__VA_ARGS__)

 #endif

// 初始化加密组件
jboolean
Java_org_aes_util_CAESEncrypt_initialize( JNIEnv* env,
                                    jobject thiz, jobject context )
{
	// 获得 Context 类
	jclass native_clazz = (*env)->GetObjectClass(env, context);

	// 得到 getPackageManager 方法的 ID
	jmethodID methodID_func = (*env)->GetMethodID(env, native_clazz,
			"getPackageManager", "()Landroid/content/pm/PackageManager;");

	// 获得应用包的管理器
	jobject package_manager = (*env)->CallObjectMethod(env, context, methodID_func);

	// 获得 PackageManager 类
	jclass pm_clazz = (*env)->GetObjectClass(env, package_manager);

	// 得到 getPackageInfo 方法的 ID
	jmethodID methodID_pm = (*env)->GetMethodID(env, pm_clazz,
			"getPackageInfo", "(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;");

	// 得到 getPackageName 方法的 ID
	jmethodID methodID_pack = (*env)->GetMethodID(env, native_clazz,
			"getPackageName", "()Ljava/lang/String;");

	// 获得当前应用的包名
	jstring application_package = (*env)->CallObjectMethod(env, context, methodID_pack);

	// 获得应用包的信息
	jobject package_info = (*env)->CallObjectMethod(env, package_manager,
			methodID_pm, application_package, 64);

	// 获得 PackageInfo 类
	jclass pi_clazz = (*env)->GetObjectClass(env, package_info);

	// 获得签名数组属性的 ID
	jfieldID fieldID_signatures = (*env)->GetFieldID(env, pi_clazz,
			"signatures", "[Landroid/content/pm/Signature;");

	// 得到签名数组，待修改
	jobjectArray signatures = (*env)->GetObjectField(env, package_info, fieldID_signatures);

	// 得到签名
	jobject signature = (*env)->GetObjectArrayElement(env, signatures, 0);

	// 获得 Signature 类，待修改
	jclass s_clazz = (*env)->GetObjectClass(env, signature);

	// 得到 hashCode 方法的 ID
	jmethodID methodID_hc = (*env)->GetMethodID(env, s_clazz, "hashCode", "()I");

	// 获得应用包的签名哈希码
	int hash_code = (*env)->CallIntMethod(env, signature, methodID_hc);
	// 测试时可以直接使用正确数据
	hash_code = -121126834;

	return Initialize(hash_code);
}

// AES加密
void
Java_org_aes_util_CAESEncrypt_AESencrypt( JNIEnv* env,
                jobject thiz, jbyteArray input, jbyteArray output, jint len, jint surplus )
{
	int i = 0;
	jbyte *body_input = (*env)->GetByteArrayElements(env, input, 0);
	jbyte *body_output = (*env)->GetByteArrayElements(env, output, 0);
	unsigned char *in = (unsigned char*) calloc(GetLength(len - 16 - surplus), sizeof(unsigned char));
	unsigned char *out = (unsigned char*) calloc(GetLength(len), sizeof(unsigned char));
	for(i = 0; i < len - 16 - surplus; i++){
		in[i] = body_input[i];
	}
	AESencrypt(in, out, len, surplus);
	for(i = 0; i < len; i++){
		body_output[i] = out[i];
	}

	(*env)->SetByteArrayRegion(env,output,0,len,body_output);
}

// AES解密
jint
Java_org_aes_util_CAESEncrypt_DecodeAESEncrypt( JNIEnv* env,
						jobject thiz, jbyteArray input, jbyteArray output, jint len )
{
	int i = 0;
	jbyte *body_input = (*env)->GetByteArrayElements(env, input, 0);
	jbyte *body_output = (*env)->GetByteArrayElements(env, output, 0);
	unsigned char *in = (unsigned char*) calloc(GetLength(len), sizeof(unsigned char));
	unsigned char *out = (unsigned char*) calloc(GetLength(len), sizeof(unsigned char));
	for( ; i < len; i++){
		in[i] = body_input[i];
	}
	int leng = DecodeAESencrypt(in, out, len);
	for(i = 0; i < leng; i++){
		body_output[i] = out[i];
	}
	(*env)->SetByteArrayRegion(env,output,0,leng,body_output);
	return leng;
}

// GZIP压缩
jint
Java_org_aes_util_CAESEncrypt_compress( JNIEnv* env,
                jobject thiz, jbyteArray input, jbyteArray output, jint len, jint predict)
{
	int num = 0;
	int i = 0;

	jbyte *body_input = (*env)->GetByteArrayElements(env, input, 0);
	jbyte *body_output = (*env)->GetByteArrayElements(env, output, 0);
	unsigned char *in = (unsigned char*) calloc(GetLength(len), sizeof(unsigned char));
	unsigned char *out = (unsigned char*) calloc(GetLength(predict), sizeof(unsigned char));
	for( ; i < len; i++){
		in[i] = body_input[i];
	}

	memset(out, 0x0, predict);
	num = zipmem(in, len, out);
	for(i = 0; i < num; i++){
		body_output[i] = out[i];
//		LOGE("------%d----------[%d]--------", i, out[i]);
//		LOGE("------%d----------[%d]--------", i, body_output[i]);
	}
	(*env)->SetByteArrayRegion(env,output,0,num,body_output);

	return num;
}

// GZIP解压
jint
Java_org_aes_util_CAESEncrypt_uncompress( JNIEnv* env,
						jobject thiz, jbyteArray input, jbyteArray output, jint len, jint predict )
{
	int num = 0;
	int i = 0;

	jbyte *body_input = (*env)->GetByteArrayElements(env, input, 0);
	jbyte *body_output = (*env)->GetByteArrayElements(env, output, 0);
	unsigned char *in = (unsigned char*) calloc(GetLength(len), sizeof(unsigned char));
	unsigned char *out = (unsigned char*) calloc(GetLength(predict), sizeof(unsigned char));
	for( ; i < len; i++){
		in[i] = body_input[i];
	}

	memset(out, 0x0, predict);
	num = unzipmem(in, len, out);
	for(i = 0; i < num; i++){
		body_output[i] = out[i];
	}
	(*env)->SetByteArrayRegion(env,output,0,num,body_output);

	return num;
}
